package systemMapperImpl

import (
	"baize/app/business/system/systemModels"
	"baize/app/datasource"
	"context"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type SysDictMapper struct {
	collectionData func(ctx context.Context) *mongo.Collection
	collectionType func(ctx context.Context) *mongo.Collection
}

func NewSysDictMapper(c *mongo.Client) *SysDictMapper {
	return &SysDictMapper{
		collectionData: func(ctx context.Context) *mongo.Collection {
			return c.Database(datasource.SysDatabase).Collection(datasource.Collection["deptData"])
		},
		collectionType: func(ctx context.Context) *mongo.Collection {
			return c.Database(datasource.SysDatabase).Collection(datasource.Collection["deptType"])
		},
	}
}

func (dm *SysDictMapper) SelectDictDataList(ctx context.Context, dictType *systemModels.SysDictDataDQL) (list []*systemModels.SysDictData, total int64) {

	filter := bson.M{}

	if dictType.DictLabel != "" {
		filter["dict_label"] = bson.M{"$regex": dictType.DictLabel, "$options": "i"}
	}
	if dictType.Status != "" {
		filter["status"] = dictType.Status
	}
	if dictType.DictType != "" {
		filter["dict_type"] = bson.M{"$regex": dictType.DictType, "$options": "i"}
	}
	return datasource.MongoQueryListAndTotal(ctx, dm.collectionData(ctx), list, filter, dictType)
}

func (dm *SysDictMapper) SelectDictDataByType(ctx context.Context, dictType string) (list []*systemModels.SysDictData) {
	filter := bson.M{"dict_type": dictType}
	cur, err := dm.collectionData(ctx).Find(ctx, filter)
	if err != nil {
		panic(err)
	}
	defer cur.Close(ctx)
	err = cur.All(context.Background(), &list)
	if err != nil {
		panic(err)
	}
	return
}

func (dm *SysDictMapper) SelectDictDataById(ctx context.Context, dictCode int64) (dictData *systemModels.SysDictData) {
	dictData = new(systemModels.SysDictData)
	filter := bson.M{"dict_code": dictCode}
	err := dm.collectionData(ctx).FindOne(ctx, filter).Decode(dictData)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return
}

func (dm *SysDictMapper) InsertDictData(ctx context.Context, dictData *systemModels.SysDictData) {
	_, err := dm.collectionData(ctx).InsertOne(ctx, dictData)
	if err != nil {
		panic(err)
	}
	return
}

func (dm *SysDictMapper) UpdateDictData(ctx context.Context, dictData *systemModels.SysDictData) {
	m := bson.M{
		"update_by":   dictData.UpdateBy,
		"update_time": dictData.UpdateTime,
		"dict_sort":   dictData.DictSort,
	}

	if dictData.DictLabel != "" {
		m["dict_label"] = dictData.DictLabel
	}
	if dictData.DictValue != "" {
		m["dict_value"] = dictData.DictValue
	}
	if dictData.DictType != "" {
		m["dict_type"] = dictData.DictType
	}
	if dictData.ListClass != "" {
		m["list_class"] = dictData.ListClass
	}
	if dictData.IsDefault != "" {
		m["is_default"] = dictData.IsDefault
	}
	if dictData.Status != "" {
		m["status"] = dictData.Status
	}
	if dictData.Remark != "" {
		m["remark"] = dictData.Remark
	}
	up := bson.M{"$set": m}

	_, err := dm.collectionData(ctx).UpdateByID(ctx, dictData.DictCode, up)
	if err != nil {
		panic(err)
	}

}

func (dm *SysDictMapper) DeleteDictDataByIds(ctx context.Context, dictCodes []int64) {
	filter := bson.M{
		"_id": bson.M{"$in": dictCodes},
	}
	_, err := dm.collectionData(ctx).DeleteMany(ctx, filter)
	if err != nil {
		panic(err)
	}
}

func (dm *SysDictMapper) CheckDictDataByTypes(ctx context.Context, dictType []string) bool {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.D{{"_id", 1}})
	type IDOnly struct {
		ID int64 `bson:"_id"`
	}
	var result IDOnly
	err := dm.collectionData(ctx).FindOne(ctx, bson.D{{"dict_type", bson.M{"$in": dictType}}}, opt).Decode(result)
	if errors.Is(err, mongo.ErrNoDocuments) {
		return false
	} else if err != nil {
		panic(err)
	}
	return true
}

func (dm *SysDictMapper) SelectDictTypeList(ctx context.Context, dictType *systemModels.SysDictTypeDQL) (list []*systemModels.SysDictType, total int64) {

	filter := bson.M{}

	if dictType.DictName != "" {
		filter["dict_name"] = bson.M{"$regex": dictType.DictName, "$options": "i"}
	}
	if dictType.Status != "" {
		filter["status"] = dictType.Status
	}
	if dictType.DictType != "" {
		filter["dict_type"] = bson.M{"$regex": dictType.DictType, "$options": "i"}
	}
	return datasource.MongoQueryListAndTotal(ctx, dm.collectionType(ctx), list, filter, dictType)
}

func (dm *SysDictMapper) SelectDictTypeAll(ctx context.Context, dictType *systemModels.SysDictTypeDQL) (list []*systemModels.SysDictType) {
	filter := bson.M{}

	if dictType.DictName != "" {
		filter["dict_name"] = bson.M{"$regex": dictType.DictName, "$options": "i"}
	}
	if dictType.Status != "" {
		filter["status"] = dictType.Status
	}
	if dictType.DictType != "" {
		filter["dict_type"] = bson.M{"$regex": dictType.DictType, "$options": "i"}
	}
	cur, err := dm.collectionType(ctx).Find(ctx, filter)
	if err != nil {
		panic(err)
	}
	defer cur.Close(ctx)
	err = cur.All(context.Background(), &list)
	if err != nil {
		panic(err)
	}
	return
}

func (dm *SysDictMapper) SelectDictTypeById(ctx context.Context, dictId int64) (dictType *systemModels.SysDictType) {
	dictType = new(systemModels.SysDictType)
	filter := bson.M{"_id": dictId}
	err := dm.collectionType(ctx).FindOne(ctx, filter).Decode(dictType)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return
}
func (dm *SysDictMapper) SelectDictTypesByIds(ctx context.Context, dictId []int64) (dictTypes []string) {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.M{"_id": 0, "dict_type": 1})
	filter := bson.M{"_id": dictId}
	cursor, err := dm.collectionType(ctx).Find(ctx, filter)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	defer cursor.Close(ctx)
	for cursor.Next(ctx) {
		var result struct {
			DictType string `bson:"dict_type"`
		}
		if err = cursor.Decode(&result); err != nil {
			panic(err)
		}
		dictTypes = append(dictTypes, result.DictType)
	}

	return dictTypes
}

func (dm *SysDictMapper) InsertDictType(ctx context.Context, dictType *systemModels.SysDictType) {
	_, err := dm.collectionType(ctx).InsertOne(ctx, dictType)
	if err != nil {
		panic(err)
	}
	return
}

func (dm *SysDictMapper) UpdateDictType(ctx context.Context, dictType *systemModels.SysDictType) {
	m := bson.M{
		"update_by":   dictType.UpdateBy,
		"update_time": dictType.UpdateTime,
	}

	if dictType.DictName != "" {
		m["dict_name"] = dictType.DictName
	}
	if dictType.DictType != "" {
		m["dict_type"] = dictType.DictType
	}
	if dictType.Status != "" {
		m["status"] = dictType.Status
	}
	if dictType.Remark != "" {
		m["remark"] = dictType.Remark
	}
	up := bson.M{"$set": m}

	_, err := dm.collectionType(ctx).UpdateByID(ctx, dictType.DictId, up)
	if err != nil {
		panic(err)
	}

}

func (dm *SysDictMapper) DeleteDictTypeByIds(ctx context.Context, dictIds []int64) {
	filter := bson.M{
		"_id": bson.M{"$in": dictIds},
	}
	_, err := dm.collectionType(ctx).DeleteMany(ctx, filter)
	if err != nil {
		panic(err)
	}
}
func (dm *SysDictMapper) CheckDictTypeUnique(ctx context.Context, dictType string) int64 {
	opt := &options.FindOneOptions{}
	opt.SetProjection(bson.D{{"_id", 1}})
	type IDOnly struct {
		ID int64 `bson:"_id"`
	}
	var result IDOnly
	err := dm.collectionType(ctx).FindOne(ctx, bson.M{"dict_type": dictType}, opt).Decode(result)
	if err != nil && !errors.Is(mongo.ErrNoDocuments, err) {
		panic(err)
	}
	return result.ID
}
